# RUN: llc -mtriple=s390x-linux-gnu -start-before=prologepilog %s -o - -mcpu=z14 \
# RUN:   -verify-machineinstrs 2>&1 | FileCheck %s
# REQUIRES: asserts
#
# Test that redundant frame addressing anchor points are removed by
# MachineLateInstrsCleanup.

--- |
  define void @fun1() { ret void }
  define void @fun2() { ret void }
  define void @fun3() { ret void }
  define void @fun4() { ret void }
  define void @fun5() { ret void }
  define void @fun6() { ret void }
  define void @fun7() { ret void }
  define void @fun8() { ret void }

  declare i32 @foo()

  @ptr = external dso_local local_unnamed_addr global ptr
---

# Test elimination of redundant LAYs in successor blocks.
# CHECK-LABEL: fun1:
# CHECK: lay %r1, 4096(%r15)
# CHECK: # %bb.1:
# CHECK-NOT: lay
# CHECK: .LBB0_2:
# CHECK-NOT: lay
---
name:            fun1
tracksRegLiveness: true
stack:
  - { id: 0, size: 5000 }
  - { id: 1, size: 2500 }
  - { id: 2, size: 2500 }

machineFunctionInfo: {}
body:             |
  bb.0 (%ir-block.0):
    liveins: $f16d
    successors: %bb.2(0x00000001), %bb.1(0x7fffffff)

    VST64 renamable $f16d, %stack.0, 0, $noreg
    VST64 renamable $f16d, %stack.0, 0, $noreg
    VST64 renamable $f16d, %stack.0, 0, $noreg
    VST64 renamable $f16d, %stack.0, 0, $noreg
    VST64 renamable $f16d, %stack.0, 0, $noreg
    VST64 renamable $f16d, %stack.1, 0, $noreg
    CHIMux undef $r0l, 3, implicit-def $cc
    BRC 14, 8, %bb.2, implicit killed $cc
    J %bb.1

  bb.1:
    liveins: $f16d
    VST64 renamable $f16d, %stack.2, 0, $noreg
    J %bb.2

  bb.2:
    liveins: $f16d
    VST64 renamable $f16d, %stack.1, 0, $noreg
    Return
...

# In this function the LAY in bb.1 will have a different offset, so the first
# LAY in bb.2 must remain.
# CHECK-LABEL: fun2:
# CHECK: lay %r1, 4096(%r15)
# CHECK: # %bb.1:
# CHECK: lay %r1, 8192(%r15)
# CHECK: .LBB1_2:
# CHECK: lay %r1, 4096(%r15)
# CHECK-NOT: lay
---
name:            fun2
tracksRegLiveness: true
stack:
  - { id: 0, size: 5000 }
  - { id: 1, size: 5000 }
  - { id: 2, size: 2500 }

machineFunctionInfo: {}
body:             |
  bb.0 (%ir-block.0):
    liveins: $f16d
    successors: %bb.2(0x00000001), %bb.1(0x7fffffff)

    VST64 renamable $f16d, %stack.0, 0, $noreg
    VST64 renamable $f16d, %stack.0, 0, $noreg
    VST64 renamable $f16d, %stack.0, 0, $noreg
    VST64 renamable $f16d, %stack.0, 0, $noreg
    VST64 renamable $f16d, %stack.0, 0, $noreg
    VST64 renamable $f16d, %stack.1, 0, $noreg
    CHIMux undef $r0l, 3, implicit-def $cc
    BRC 14, 8, %bb.2, implicit killed $cc
    J %bb.1

  bb.1:
    liveins: $f16d
    VST64 renamable $f16d, %stack.2, 0, $noreg
    J %bb.2

  bb.2:
    liveins: $f16d
    VST64 renamable $f16d, %stack.1, 0, $noreg
    VST64 renamable $f16d, %stack.1, 0, $noreg
    Return
...

# Test case with a loop (with room for improvement: since %r1 is not clobbered
# inside the loop only the first LAY is needed).
# CHECK-LABEL: fun3:
# CHECK: lay %r1, 4096(%r15)
# CHECK: .LBB2_1:
# CHECK: lay %r1, 4096(%r15)
# CHECK: .LBB2_2:
# CHECK-NOT: lay %r1, 4096(%r15)
---
name:            fun3
tracksRegLiveness: true
stack:
  - { id: 0, size: 5000 }
  - { id: 1, size: 2500 }
  - { id: 2, size: 2500 }

machineFunctionInfo: {}
body:             |
  bb.0 (%ir-block.0):
    liveins: $f16d
    successors: %bb.2(0x00000001), %bb.1(0x7fffffff)

    VST64 renamable $f16d, %stack.0, 0, $noreg
    VST64 renamable $f16d, %stack.0, 0, $noreg
    VST64 renamable $f16d, %stack.0, 0, $noreg
    VST64 renamable $f16d, %stack.0, 0, $noreg
    VST64 renamable $f16d, %stack.0, 0, $noreg
    VST64 renamable $f16d, %stack.1, 0, $noreg
    CHIMux undef $r0l, 3, implicit-def $cc
    BRC 14, 8, %bb.2, implicit killed $cc
    J %bb.1

  bb.1:
    liveins: $f16d
    successors: %bb.2(0x00000001), %bb.1(0x7fffffff)

    VST64 renamable $f16d, %stack.2, 0, $noreg
    CHIMux undef $r0l, 3, implicit-def $cc
    BRC 14, 8, %bb.1, implicit killed $cc
    J %bb.2

  bb.2:
    liveins: $f16d
    VST64 renamable $f16d, %stack.1, 0, $noreg
    Return
...

# Test case with a call which clobbers r1: the second LAY after the call is needed.
# CHECK-LABEL: fun4:
# CHECK: lay %r1, 4096(%r15)
# CHECK: brasl
# CHECK: lay %r1, 4096(%r15)
---
name:            fun4
tracksRegLiveness: true
stack:
  - { id: 0, size: 5000 }
  - { id: 1, size: 2500 }

machineFunctionInfo: {}
body:             |
  bb.0 (%ir-block.0):
    liveins: $f16d

    VST64 renamable $f16d, %stack.0, 0, $noreg
    VST64 renamable $f16d, %stack.0, 0, $noreg
    VST64 renamable $f16d, %stack.0, 0, $noreg
    VST64 renamable $f16d, %stack.0, 0, $noreg
    VST64 renamable $f16d, %stack.0, 0, $noreg
    VST64 renamable $f16d, %stack.1, 0, $noreg
    ADJCALLSTACKDOWN 0, 0
    CallBRASL @foo, csr_systemz_elf, implicit-def dead $r14d, implicit-def dead $cc, implicit $fpc, implicit-def $r2l
    ADJCALLSTACKUP 0, 0
    $f17d = IMPLICIT_DEF
    VST64 renamable $f17d, %stack.1, 0, $noreg
    Return
...

# Test case where index reg is loaded instead of using an LAY. Only one LGHI is needed.
# CHECK-LABEL: fun5:
# CHECK: lghi %r1, 4096
# CHECK-NOT: lghi
---
name:            fun5
tracksRegLiveness: true
stack:
  - { id: 0, size: 5000 }
  - { id: 1, size: 2500 }

machineFunctionInfo: {}
body:             |
  bb.0 (%ir-block.0):
    liveins: $f16d

    VST64 renamable $f16d, %stack.0, 0, $noreg
    VST64 renamable $f16d, %stack.0, 0, $noreg
    VST64 renamable $f16d, %stack.0, 0, $noreg
    VST64 renamable $f16d, %stack.0, 0, $noreg
    VST64 renamable $f16d, %stack.0, 0, $noreg
    $f0q = nofpexcept LXEB %stack.1, 0, $noreg, implicit $fpc
    $f1q = nofpexcept LXEB %stack.1, 0, $noreg, implicit $fpc
    Return
...

# Test where the constant is a Global. Only one LARL is needed.
# CHECK-LABEL: fun6:
# CHECK: larl %r1, ptr
# CHECK-NOT: larl
---
name:            fun6
alignment:       16
tracksRegLiveness: true
tracksDebugUserValues: true
frameInfo:
  maxAlignment:    1
  maxCallFrameSize: 0
fixedStack:
  - { id: 0, offset: -160, size: 8, alignment: 8 }
machineFunctionInfo: {}
body:             |
  bb.0:
    successors: %bb.2(0x30000000), %bb.1(0x50000000)

    renamable $r1d = LARL @ptr
    CGHSI killed renamable $r1d, 0, 0, implicit-def $cc :: (volatile dereferenceable load (s64) from @ptr)
    BRC 14, 8, %bb.2, implicit killed $cc
    J %bb.1

  bb.1:
    renamable $r1d = LARL @ptr
    MVGHI killed renamable $r1d, 0, 0

  bb.2:
    Return

...

# Load of an invariant location (GOT). Only one LGRL is needed.
# CHECK-LABEL: fun7:
# CHECK: lgrl %r1, ptr
# CHECK-NOT: lgrl
---
name:            fun7
alignment:       16
tracksRegLiveness: true
tracksDebugUserValues: true
frameInfo:
  maxAlignment:    1
  maxCallFrameSize: 0
fixedStack:
  - { id: 0, offset: -160, size: 8, alignment: 8 }
machineFunctionInfo: {}
body:             |
  bb.0:
    successors: %bb.2(0x30000000), %bb.1(0x50000000)
  
    renamable $r1d = LGRL @ptr :: (load (s64) from got)
    CGHSI killed renamable $r1d, 0, 0, implicit-def $cc :: (volatile dereferenceable load (s64) from @ptr)
    BRC 14, 8, %bb.2, implicit killed $cc
    J %bb.1
  
  bb.1:
    renamable $r1d = LGRL @ptr :: (load (s64) from got)
    MVGHI killed renamable $r1d, 0, 0
  
  bb.2:
    Return

...

# Load from constant pool. Only one LARL is needed.
# CHECK-LABEL: fun8:
# CHECK: larl %r1, .LCPI7_0
# CHECK-NOT: larl
---
name:            fun8
alignment:       16
tracksRegLiveness: true
tracksDebugUserValues: true
liveins:
  - { reg: '$f0s' }
frameInfo:
  maxAlignment:    1
  maxCallFrameSize: 0
fixedStack:
  - { id: 0, offset: -160, size: 8, alignment: 8 }
constants:
  - id:              0
    value:           float 0x43E0000000000000
    alignment:       4
machineFunctionInfo: {}
body:             |
  bb.0 (%ir-block.0):
    successors: %bb.1, %bb.2
    liveins: $f0s

    renamable $r1d = LARL %const.0
    renamable $f1s = LE killed renamable $r1d, 0, $noreg :: (load (s32) from constant-pool)
    nofpexcept CEBR renamable $f0s, renamable $f1s, implicit-def $cc, implicit $fpc
    BRC 15, 11, %bb.2, implicit killed $cc

  bb.1:
    liveins: $f0s

    J %bb.3

  bb.2 (%ir-block.0):
    liveins: $f0s, $f1s

    renamable $r1d = LARL %const.0
    renamable $f1s = LE killed renamable $r1d, 0, $noreg :: (load (s32) from constant-pool)

  bb.3 (%ir-block.0):
    liveins: $r2d

    Return

...
